import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.Channel;
import java.nio.channels.DatagramChannel;
import java.nio.channels.FileChannel;
import java.nio.channels.Pipe;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class Test {
	public static void main(String[] args) throws IOException {

		Test test = new Test();
		test.test();

	}

	public void test() throws IOException {
		RandomAccessFile aFile = new RandomAccessFile("1.txt", "rw");
		FileChannel inChannel = aFile.getChannel();

		ByteBuffer buf = ByteBuffer.allocate(48);
		int bytesRead = inChannel.read(buf);
		while (bytesRead != -1) {
			buf.flip(); // 强Buffer从写模式切换到读模式
			while (buf.hasRemaining()) {

				System.out.print((char) buf.get());
			}
			buf.clear();
			bytesRead = inChannel.read(buf);

		}
		aFile.close();
	}

	public void testScatterRead(FileChannel channel) throws IOException {
		ByteBuffer header = ByteBuffer.allocate(128);
		ByteBuffer body = ByteBuffer.allocate(1024);

		ByteBuffer[] bufferArray = { header, body };
		channel.read(bufferArray);
	}

	public void testGatherWrite(FileChannel channel) throws IOException {
		ByteBuffer header = ByteBuffer.allocate(128);
		ByteBuffer body = ByteBuffer.allocate(1024);

		ByteBuffer[] bufferArray = { header, body };
		channel.write(bufferArray);
	}

	public void testTransfer() throws IOException {
		RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
		FileChannel fromChannel = fromFile.getChannel();

		RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");
		FileChannel toChannel = toFile.getChannel();

		long position = 0;
		long count = fromChannel.size();

		toChannel.transferFrom(fromChannel, position, count);

		// fromChannel.transferTo(position, count, toChannel);
	}

	public void seletorTest() throws IOException {
		Selector selector = Selector.open();
		
		SocketChannel sc = SocketChannel.open();
		sc.connect(new InetSocketAddress("http://github.com", 80));
		sc.configureBlocking(false);
		/*
		 * 与Selector一起使用时，Channel必须处于非阻塞模式下。
		 * 这意味着不能将FileChannel与Selector一起使用，
		 * 因为FileChannel不能切换到非阻塞模式。而套接字通道都可以。
		 */
		SelectionKey key = sc.register(selector, SelectionKey.OP_READ);
		int readySet = key.readyOps();
		key.isAcceptable();
		key.isConnectable();
		key.isReadable();
		key.isWritable();
		
		Channel channel = key.channel();
		Selector slc = key.selector();
		
		// 附加对象
		key.attach(new Object());
		Object obj = key.attachment();
		sc.register(selector, SelectionKey.OP_READ, new Object());
		
		//遍历就绪信道
		Set selectedKeys = selector.selectedKeys();
		Iterator keyIterator = selectedKeys.iterator();
		while (keyIterator.hasNext()) {
			SelectionKey tempKey = (SelectionKey) keyIterator.next();
			if (key.isAcceptable()) {
				
			} else if (key.isConnectable()) {
				
			} else if (key.isReadable()) {
				
			} else if (key.isWritable()) {
				
			}
			/**
			 * 注意每次迭代末尾的keyIterator.remove()调用。
			 * Selector不会自己从已选择键集中移除SelectionKey实例。
			 * 必须在处理完通道时自己移除。下次该通道变成就绪时，
			 * Selector会再次将其放入已选择键集中。 
			 */
			keyIterator.remove();
		}
	}
	
	// TCP
	public void testServerSocketChannel() throws IOException {
		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		serverSocketChannel.socket().bind(new InetSocketAddress(9999));
		serverSocketChannel.configureBlocking(false);
		while (true) {
			SocketChannel socketChannel = serverSocketChannel.accept();
			//...
		}
	}
	
	// UDP
	public void testUDPChannel() throws IOException {
		DatagramChannel channel = DatagramChannel.open();
		channel.socket().bind(new InetSocketAddress(9999));
		//从指定地址收发数据
		channel.connect(new InetSocketAddress("www.baidu.com", 80));
		channel.configureBlocking(false);
		
		ByteBuffer buf = ByteBuffer.allocate(48);
		buf.clear();
		channel.receive(buf);
		
		//发送数据
		channel.send(buf, new InetSocketAddress("https://github.com", 80));
	}
	
	public void testPipe() throws IOException {
		Pipe pipe = Pipe.open();
		// 获取写通道
		Pipe.SinkChannel sinkChannel = pipe.sink();
		String newData = "new Data" + System.currentTimeMillis();
		ByteBuffer buf = ByteBuffer.allocate(48);
		buf.clear();
		buf.put(newData.getBytes());
		
		buf.flip();
		
		while (buf.hasRemaining()) {
			sinkChannel.write(buf);
		}
		
		// 获取读通道
		Pipe.SourceChannel sourceChannel = pipe.source();
		ByteBuffer bufRead = ByteBuffer.allocate(48);
		int byteRead = sourceChannel.read(bufRead);
		
		
	}
}
